from datetime import datetime
import json
import logging
from typing import List, Optional

from bson import ObjectId
from pydantic import ValidationError

from app.core.database import db
from app.models.schemas import Book

logger = logging.getLogger(__name__)

class BookService:
    @staticmethod
    async def feed_book_to_elf(elf_id: str, book_id: str) -> dict:
        """
        精灵阅读书籍：
        1. 更新MongoDB中书籍的elf_list
        2. 更新PostgreSQL中精灵的智力属性
        3. 同步更新精灵profile档案
        """
        async with db.pg_pool.acquire() as pg_conn:
            try:
                async with pg_conn.transaction():
                    elf_data = await pg_conn.fetchrow(
                        """
                        SELECT elf_id, user_id, basic_info, interaction_summary
                        FROM elf_profile 
                        WHERE elf_id = $1
                        """,
                        elf_id
                    )
                    
                    if not elf_data:
                        raise ValueError(f"精灵 {elf_id} 不存在")
                    
                    basic_info = json.loads(elf_data['basic_info'])
                    interaction_summary = json.loads(elf_data['interaction_summary'])
                    
                    current_intelligence = basic_info.get('intelligence', 0)
                    new_intelligence = current_intelligence + 50
                    basic_info['intelligence'] = new_intelligence
                    
                    mongo_db = db.get_mongo_db()
                    book_collection = mongo_db.elf_book
                    
                    try:
                        book_obj_id = ObjectId(book_id)
                    except:
                        raise ValueError(f"无效的书籍ID: {book_id}")
                    
                    book = await book_collection.find_one({"_id": book_obj_id})
                    if not book:
                        raise ValueError(f"书籍 {book_id} 不存在")
                    
                    elf_list = book.get('elf_list', [])
                    if elf_id in elf_list:
                        return {
                            "success": False,
                            "message": "精灵已经阅读过这本书",
                            "intelligence_before": current_intelligence,
                            "intelligence_after": current_intelligence,
                            "books_read": len(elf_list)
                        }

                    mongo_updated = False

                    mongo_update_result = await book_collection.update_one(
                        {"_id": book_obj_id},
                        {
                            "$addToSet": {"elf_list": elf_id},
                            "$set": {"updated_at": datetime.now()}
                        }
                    )

                    if mongo_update_result.modified_count == 0:
                        logger.info("重复喂养书籍被检测并跳过", extra={"elf_id": elf_id, "book_id": book_id})
                        return {
                            "success": False,
                            "message": "精灵已经阅读过这本书",
                            "intelligence_before": current_intelligence,
                            "intelligence_after": current_intelligence,
                            "books_read": len(elf_list)
                        }

                    mongo_updated = True
                    books_read = interaction_summary.get('books_read', [])
                    if book_id not in books_read:
                        books_read.append(book_id)
                    interaction_summary['books_read'] = books_read
                    interaction_summary['last_book_read'] = {
                        "book_id": book_id,
                        "book_name": book.get('book_name'),
                        "read_at": datetime.now().isoformat()
                    }
                    interaction_summary['total_books_read'] = len(books_read)

                    try:
                        await pg_conn.execute(
                            """
                            UPDATE elf_profile 
                            SET basic_info = $1,
                                interaction_summary = $2,
                                updated_at = $3
                            WHERE elf_id = $4
                            """,
                            json.dumps(basic_info),
                            json.dumps(interaction_summary),
                            datetime.now(),
                            elf_id
                        )
                    except Exception:
                        if mongo_updated:
                            await book_collection.update_one(
                                {"_id": book_obj_id},
                                {
                                    "$pull": {"elf_list": elf_id},
                                    "$set": {"updated_at": datetime.now()}
                                }
                            )
                        raise

                    redis_client = db.get_redis_client()
                    if redis_client:
                        cache_key = f"elf_books:{elf_id}"
                        try:
                            await redis_client.delete(cache_key)
                        except Exception as cache_err:
                            logger.warning(
                                "缓存删除失败",
                                extra={"cache_key": cache_key, "error": str(cache_err)}
                            )

                    logger.info(f"精灵 {elf_id} 成功阅读书籍 {book_id}，智力从 {current_intelligence} 提升到 {new_intelligence}")

                    return {
                        "success": True,
                        "message": f"精灵成功阅读《{book.get('book_name')}》",
                        "intelligence_before": current_intelligence,
                        "intelligence_after": new_intelligence,
                        "books_read": len(books_read)
                    }
                    
            except Exception as e:
                logger.error(f"喂养书籍失败: {e}")
                raise
    
    @staticmethod
    async def remove_book_from_elf(elf_id: str, book_id: str) -> dict:
        """
        删除精灵的阅读记录
        """
        mongo_db = db.get_mongo_db()
        book_collection = mongo_db.elf_book
        
        try:
            book_obj_id = ObjectId(book_id)
        except:
            raise ValueError(f"无效的书籍ID: {book_id}")
        
        result = await book_collection.update_one(
            {"_id": book_obj_id},
            {
                "$pull": {"elf_list": elf_id},
                "$set": {"updated_at": datetime.now()}
            }
        )

        if result.modified_count > 0:
            async with db.pg_pool.acquire() as pg_conn:
                elf_data = await pg_conn.fetchrow(
                    "SELECT interaction_summary FROM elf_profile WHERE elf_id = $1",
                    elf_id
                )
                
                if elf_data:
                    interaction_summary = json.loads(elf_data['interaction_summary'])
                    books_read = interaction_summary.get('books_read', [])
                    if book_id in books_read:
                        books_read.remove(book_id)
                        interaction_summary['books_read'] = books_read
                        interaction_summary['total_books_read'] = len(books_read)

                        last_book = interaction_summary.get('last_book_read')
                        if last_book and last_book.get('book_id') == book_id:
                            interaction_summary['last_book_read'] = None
                        
                        await pg_conn.execute(
                            """
                            UPDATE elf_profile 
                            SET interaction_summary = $1, updated_at = $2
                            WHERE elf_id = $3
                            """,
                            json.dumps(interaction_summary),
                            datetime.now(),
                            elf_id
                        )

            redis_client = db.get_redis_client()
            if redis_client:
                cache_key = f"elf_books:{elf_id}"
                try:
                    await redis_client.delete(cache_key)
                except Exception as cache_err:
                    logger.warning(
                        "缓存删除失败",
                        extra={"cache_key": cache_key, "error": str(cache_err)}
                    )

            logger.info(f"成功删除精灵 {elf_id} 的书籍 {book_id} 阅读记录")
            return {"success": True, "message": "阅读记录已删除"}
        else:
            return {"success": False, "message": "未找到相关阅读记录"}
    
    @staticmethod
    async def get_elf_books(elf_id: str) -> List[Book]:
        """
        获取精灵已阅读的所有书籍
        """
        mongo_db = db.get_mongo_db()
        book_collection = mongo_db.elf_book
        
        redis_client = db.get_redis_client()
        cache_key = f"elf_books:{elf_id}"
        
        if redis_client:
            cached = await redis_client.get(cache_key)
            if cached:
                try:
                    cached_books = json.loads(cached)
                    books_from_cache = [Book(**book_data) for book_data in cached_books]
                    logger.info(f"从缓存获取精灵 {elf_id} 的书籍列表")
                    return books_from_cache
                except (json.JSONDecodeError, ValidationError, TypeError) as cache_err:
                    logger.warning(
                        "缓存数据解析失败，将回退到数据库查询",
                        extra={"cache_key": cache_key, "error": str(cache_err)}
                    )

        books = []
        async for book in book_collection.find({"elf_list": elf_id}):
            book['_id'] = str(book['_id'])
            books.append(Book(**book))
        
        if redis_client and books:
            await redis_client.setex(
                cache_key, 
                300,
                json.dumps([book.dict() for book in books], default=str)
            )
        
        logger.info(f"精灵 {elf_id} 已阅读 {len(books)} 本书籍")
        return books
    
    @staticmethod
    async def get_all_books(min_age: Optional[int] = None, 
                           max_age: Optional[int] = None,
                           book_type: Optional[str] = None,
                           region: Optional[str] = None) -> List[Book]:
        """
        获取所有可用书籍（带筛选条件）
        """
        mongo_db = db.get_mongo_db()
        book_collection = mongo_db.elf_book
        
        query = {}
        if min_age is not None:
            query["min_age"] = {"$lte": min_age}
        if max_age is not None:
            query["max_age"] = {"$gte": max_age}
        if book_type:
            query["book_type"] = book_type
        if region:
            query["region"] = region
        
        books = []
        async for book in book_collection.find(query).limit(100):
            book['_id'] = str(book['_id'])
            books.append(Book(**book))
        
        return books
